package com.gjintel.workflow.trade.controller;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;


import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import antlr.StringUtils;

import net.sf.json.JSONObject;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.apache.commons.io.FilenameUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


import com.gjintel.framework.util.CommUtil;
import com.gjintel.sdk.base.dao.Page;
import com.gjintel.sdk.util.ProcessDefinitionCache;
import com.gjintel.sdk.util.StringUtil;
import com.gjintel.workflow.UserUtil;
import com.gjintel.workflow.trade.dto.ProcessInstanceDto;
import com.gjintel.workflow.trade.service.IWorkflowProcessDefinitionService;
import com.gjintel.workflow.trade.service.IWorkflowTraceService;


@SuppressWarnings("unchecked")
@RequestMapping("/workflow")
@Controller
public class ActivitiController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    protected IWorkflowTraceService traceService;

    @Autowired
    protected IWorkflowProcessDefinitionService workflowProcessDefinitionService;

    protected static Map<String, ProcessDefinition> PROCESS_DEFINITION_CACHE = new HashMap<String, ProcessDefinition>();

    @RequestMapping(value = "/process/list")
    public ModelAndView processList() {
        ModelAndView mav = new ModelAndView("workflow/process-list");


		/*
         * 保存两个对象，一个是ProcessDefinition（流程定义），一个是Deployment（流程部署）
		 */
        List<Object[]> objects = new ArrayList<Object[]>();

        List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list();
        for (ProcessDefinition processDefinition : processDefinitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            objects.add(new Object[]{processDefinition, deployment});
        }
        mav.addObject("objects", objects);

        return mav;
    }

    /**
     * 部署全部流程
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/redeploy/all")
    public String redeployAll() throws Exception {
        workflowProcessDefinitionService.deployAllFromClasspath();
        return "redirect:/workflow/processlist";
    }

    /**
     * 读取资源，通过部署ID
     *
     * @param deploymentId 流程部署的ID
     * @param resourceName 资源名称(foo.xml|foo.png)
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/resource/deployment")
    public void loadByDeployment(@RequestParam("deploymentId") String deploymentId, @RequestParam("resourceName") String resourceName,
                                 HttpServletResponse response) throws Exception {
        InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 读取资源，通过流程ID
     *
     * @param resourceType      资源类型(xml|image)
     * @param processInstanceId 流程实例ID
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/resource/process-instance")
    public void loadByProcessInstance(@RequestParam("type") String resourceType, @RequestParam("pid") String processInstanceId, HttpServletResponse response)
            throws Exception {
        InputStream resourceAsStream = null;
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId())
                .singleResult();

        String resourceName = "";
        if (resourceType.equals("image")) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if (resourceType.equals("xml")) {
            resourceName = processDefinition.getResourceName();
        }
        resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 删除部署的流程，级联删除流程实例
     *
     * @param deploymentId 流程部署ID
     */
    @RequestMapping(value = "/process/delete")
    public String delete(@RequestParam("deploymentId") String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
        return "redirect:/workflow/process/list";
    }

    /**
     * 输出跟踪流程信息
     *
     * @param processInstanceId
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/process/trace")
    public ModelAndView traceProcess(String processInstanceId) throws Exception {
        ModelAndView mv = new ModelAndView("workflow/process-trace");
        List<Map<String, Object>> activityInfos = traceService.traceProcess(processInstanceId);
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        mv.addObject("activityInfos", activityInfos);
        mv.addObject("processInstance", processInstance);
        mv.addObject("processDefinition", ProcessDefinitionCache.get(processInstance.getProcessDefinitionId()));
        return mv;
    }


    @RequestMapping(value = "/deploy")
    public String deploy(@RequestParam(value = "file", required = false) MultipartFile file) {

        String fileName = file.getOriginalFilename();

        try {
            InputStream fileInputStream = file.getInputStream();

            String extension = FilenameUtils.getExtension(fileName);
            if (extension.equals("zip") || extension.equals("bar")) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                repositoryService.createDeployment().addZipInputStream(zip).deploy();
            } else if (extension.equals("png")) {
                repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            } else if (fileName.indexOf("bpmn20.xml") != -1) {
                repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            } else if (extension.equals("bpmn")) {
            /*
             * bpmn扩展名特殊处理，转换为bpmn20.xml
	         */
                String baseName = FilenameUtils.getBaseName(fileName);
                repositoryService.createDeployment().addInputStream(baseName + ".bpmn20.xml", fileInputStream).deploy();
            } else {
                throw new ActivitiException("no support file type of " + extension);
            }
        } catch (Exception e) {
            // logger.error("error on deploy process, because of file input stream", e);
        }

        return "redirect:/workflow/process-list";
    }

    /**
     * 待办任务--Portlet
     */
    @RequestMapping(value = "/task/todo/list")
    @ResponseBody
    public List<Map<String, Object>> todoList(HttpSession session) throws Exception {
        User user = UserUtil.getUserFromSession(session);
        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm");

        // 已经签收的任务
        List<Task> todoList = taskService.createTaskQuery().taskAssignee(user.getId()).active().list();
        for (Task task : todoList) {
            String processDefinitionId = task.getProcessDefinitionId();
            ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);

            Map<String, Object> singleTask = packageTaskInfo(sdf, task, processDefinition);
            singleTask.put("status", "todo");
            result.add(singleTask);
        }

        // 等待签收的任务
        List<Task> toClaimList = taskService.createTaskQuery().taskCandidateUser(user.getId()).active().list();
        for (Task task : toClaimList) {
            String processDefinitionId = task.getProcessDefinitionId();
            ProcessDefinition processDefinition = getProcessDefinition(processDefinitionId);

            Map<String, Object> singleTask = packageTaskInfo(sdf, task, processDefinition);
            singleTask.put("status", "claim");
            result.add(singleTask);
        }

        return result;
    }

    private Map<String, Object> packageTaskInfo(SimpleDateFormat sdf, Task task, ProcessDefinition processDefinition) {
        Map<String, Object> singleTask = new HashMap<String, Object>();
        singleTask.put("id", task.getId());
        singleTask.put("name", task.getName());
        singleTask.put("createTime", sdf.format(task.getCreateTime()));
        singleTask.put("pdname", processDefinition.getName());
        singleTask.put("pdversion", processDefinition.getVersion());
        singleTask.put("pid", task.getProcessInstanceId());
        return singleTask;
    }

    private ProcessDefinition getProcessDefinition(String processDefinitionId) {
        ProcessDefinition processDefinition = PROCESS_DEFINITION_CACHE.get(processDefinitionId);
        if (processDefinition == null) {
            processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
            PROCESS_DEFINITION_CACHE.put(processDefinitionId, processDefinition);
        }
        return processDefinition;
    }

    /**
     * 挂起、激活流程定义
     */
    @RequestMapping(value = "/process/processdefinition/update/{state}/{processDefinitionId}")
    public String updateState(@PathVariable("state") String state, @PathVariable("processDefinitionId") String processDefinitionId,
                              RedirectAttributes redirectAttributes) {
        if (state.equals("active")) {
            redirectAttributes.addFlashAttribute("message", "已激活ID为[" + processDefinitionId + "]的流程定义。");
            repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
        } else if (state.equals("suspend")) {
            repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            redirectAttributes.addFlashAttribute("message", "已挂起ID为[" + processDefinitionId + "]的流程定义。");
        }
        return "redirect:/workflow/process/list";
    }


    /**
     * 挂起、激活流程实例
     */
    @RequestMapping(value = "processdefinition/update/{state}/{processInstanceId}")
    public String updateRunningState(@PathVariable("state") String state, @PathVariable("processInstanceId") String processInstanceId,
                               RedirectAttributes redirectAttributes) {
        if (state.equals("active")) {
            redirectAttributes.addFlashAttribute("message", "已激活ID为[" + processInstanceId + "]的流程定义。");
            //repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
            runtimeService.activateProcessInstanceById(processInstanceId);

        } else if (state.equals("suspend")) {
            //repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            runtimeService.suspendProcessInstanceById(processInstanceId);
            redirectAttributes.addFlashAttribute("message", "已挂起ID为[" + processInstanceId + "]的流程定义。");
        }
        return "redirect:/workflow/running-manage-list.jsp";
    }

    /**
     * @param model
     * @param request
     * @return
     * @description 运行中流程列表
     * @author wei
     * @date 2016-7-19
     */
    @RequestMapping(value = "/running")
    @ResponseBody
    public JSONObject running(Page page, String businessKey) {
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        if (org.apache.commons.lang.StringUtils.isBlank(businessKey) == false) {
            processInstanceQuery.processInstanceBusinessKey(businessKey);
        }
        //查询数据(分页)
        List<ProcessInstance> list = processInstanceQuery.listPage(page.getFirst() - 1, page.getPageSize());


        //数据的总数
        long count = processInstanceQuery.count();

        List<ProcessInstanceDto> result = new ArrayList<ProcessInstanceDto>();

        ProcessDefinitionCache.setRepositoryService(repositoryService);

        //处理数据
        for (ProcessInstance pi : list) {
            ProcessInstanceDto dto = new ProcessInstanceDto();
            dto.setId(pi.getId());
            dto.setNodeName(ProcessDefinitionCache.getActivityName(pi.getProcessDefinitionId(), pi.getActivityId()));
            dto.setProcessDefinitionId(pi.getProcessDefinitionId());
            //dto.setProcessDefinition(ProcessDefinitionCache.get(pi.getProcessDefinitionId()));
            dto.setProcessInstanceId(pi.getProcessInstanceId());
            dto.setSuspended(pi.isSuspended());
            dto.setDeploymentId(pi.getDeploymentId());
            dto.setBusinessKey(pi.getBusinessKey());
            result.add(dto);
        }

        //设置分页的数据
        page.setResult(result);
        page.setTotalCount(count);
        return CommUtil.getPageJSONData(page, true);
    }

    /**
     * 读取资源，通过部署ID
     *
     * @param processDefinitionId 流程定义
     * @param resourceType        资源类型(xml|image)
     * @throws Exception
     */
    @RequestMapping(value = "/resource/read")
    public void loadResourceByDeployment(@RequestParam("processDefinitionId") String processDefinitionId, @RequestParam("resourceType") String resourceType,
                                         HttpServletResponse response) throws Exception {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        String resourceName = "";
        if (resourceType.equals("image")) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if (resourceType.equals("xml")) {
            resourceName = processDefinition.getResourceName();
        }
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 解决bug方法
     *
     * @param processInstanceId
     * @return
     */
    @RequestMapping(value = "/solveBug")
    @ResponseBody
    public String solveBug(String pid) {
        Map<String, Object> v = new HashMap<String, Object>();
        v.put("tenderPass", true);
        v.put("timeHit", StringUtil.getISODate("2017-01-05 23:59:59"));
        Task task = taskService.createTaskQuery().processInstanceId("32830").singleResult();//"32830"
        taskService.complete(task.getId(), v);

        Task task2 = taskService.createTaskQuery().processInstanceId("32830").singleResult();//"32830"
        taskService.complete(task2.getId(), v);

        System.err.println("ok");


        return "ok";
    }
}
